package parser;

import com.github.javaparser.ParseException;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.thoughtworks.qdox.model.JavaConstructor;
import com.thoughtworks.qdox.model.JavaParameter;
import entity.ConstructorEntity;
import entity.VariableEntity;
import type.AccessModifierEnum;

import java.util.ArrayList;
import java.util.List;

public class ConstructorParser {
    public static ConstructorEntity getConstructorEntity(JavaConstructor jc) throws ParseException {
        if (jc != null) {
            ConstructorEntity entity = new ConstructorEntity();
            entity.setCode(jc.getCodeBlock());
            entity.setAccessModifierEnum(getAccessModifier(jc));
            entity.setDeclarationClass(jc.getDeclaringClass());
            entity.setArguments(getArguments(jc));
            // JavaParser 传入字符串解析方法调用关系
            entity.setCalledMethods(getCalledMethods(jc.toString()));
        }
        return null;
    }

    /**
     * 获取调用的方法列表，并根据 imports 匹配到全限定名
     */
    public static List<MethodCallExpr> getCalledMethods(String constructor_code) {
        String str = "private void C" + constructor_code.substring(constructor_code.indexOf('('));  // 为提取调用关系，把构造器当作方法解析
        MethodDeclaration md = StaticJavaParser.parseMethodDeclaration(str);
        return md.findAll(MethodCallExpr.class);
    }

    /**
     * 获取构造器参数
     */
    public static List<VariableEntity> getArguments(JavaConstructor jc) throws ParseException {
        List<VariableEntity> arguments = null;
        List<JavaParameter> jps = jc.getParameters();
        if (jps != null && !jps.isEmpty()) {
            arguments = new ArrayList<>();
            for (JavaParameter jp : jps) {
                arguments.add(VariableParser.createVariableEntity(jp));
            }
        }
        return arguments;
    }

    /**
     * 获取访问修饰符
     */
    public static AccessModifierEnum getAccessModifier(JavaConstructor cls) {
        if (cls.isPublic()) {
            return AccessModifierEnum.PUBLIC;
        } else if (cls.isPrivate()) {
            return AccessModifierEnum.PRIVATE;
        } else if (cls.isProtected()) {
            return AccessModifierEnum.PROTECTED;
        } else {
            return AccessModifierEnum.DEFAULT;
        }
    }
}
